#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>
#include <stdlib.h>

union semun{	int              val;    /* Value for SETVAL */
		struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
		unsigned short  *array;  /* Array for GETALL, SETALL */
	       	struct seminfo  *__buf;  /* Buffer for IPC_INFO(Linux-specific) */
};

int main(int argc, char **argv)
{
	key_t		key ;
	int		semid ;
	union semun	sem_union ;
	int		pid ;
	struct sembuf	sem_buf ;

	key = ftok(".",128) ;
	if( key == -1 )
	{
		printf("ftok() failed: %s\n", strerror(errno)) ;
		return -1 ;
	}
	printf("ftok sucessful,and key = %d\n", key) ;

	semid = semget(key, 1, IPC_CREAT|0666) ;
	if(semid < 0)
	{
		printf("semget() failed: %s\n", strerror(errno)) ;
		return -2 ;
	}
	printf("semget sucessful, and semid = %d\n", semid) ;


	sem_union.val = 0 ;
	if( semctl(semid, 0, SETVAL, sem_union) < 0 ) //对第一个信号初始化
	{
		printf("semctl init failed: %s\n", strerror(errno)) ;
		return -3 ;
	}

	pid = fork() ;
	if(pid < 0)
	{
		printf("fork failed: %s\n", strerror(errno)) ;
		return -4 ;
	}

	if(pid == 0) //Child process
	{
		printf("Child process[%d] is running,and can do someting in here...\n", getpid()) ;
		sleep(3) ;
		printf("Child process do something over...\n");		
		sem_buf.sem_num = 0 ;                  //V操作
		sem_buf.sem_op = 1 ;
		sem_buf.sem_flg = SEM_UNDO ;
		if( semop(semid, &sem_buf, 1) < 0)
		{
			printf("semop V operator failed: %s\n", strerror(errno)) ;
			goto cleanup ;
		}
		printf("Child process will exit!\n") ;
		sleep(1) ;
		exit(0) ;
		
	}
	if(pid > 0) //Parent process
	{
		printf("Parent process[%d] is running...\n", getpid()) ;
		printf("Parent can't continue until child finish V operator!\n") ;	
		sem_buf.sem_num = 0 ;                  //P操作
		sem_buf.sem_op = -1 ;
		sem_buf.sem_flg = SEM_UNDO ;
		if( semop(semid, &sem_buf, 1) < 0)
		{
			printf("semop P operator failed: %s\n", strerror(errno)) ;
			goto cleanup ;
		}
		printf("Parent process finish P operator\n") ;
		sleep(1) ;
		printf("Perent process destroy semaphore and exit\n") ;
		semctl(semid, 0, IPC_RMID) ;
		
	}


cleanup:
	semctl(semid, 0, IPC_RMID) ;


	return 0 ;
}
